/**
 * 20.1.9：移除重写的copy和clone方法
 * 20.12.14：增加setRect方法，当需用同一相机渲染多视口时设置个性化的检测区域
 * 210903：修改片元着色器代码，自定义clampR代替clamp函数，以修正在没有独显的老旧笔记本上显示异常的问题
 */
let THREE=require('three');
import VirtualPlane from "./virtual-plane";

/**
 * 提示点击热区
 *
 @param values {object}
 size:0.5, 尺寸大小
 opacity:1, 不透明度
 color: new THREE.Color(0.3, 1, 0), 中心区域颜色
 radius: 1, 外圈半径

 通过material编辑通用材质属性
 通过geometry编辑通用几何属性
 */
export default class HotZone extends VirtualPlane{
    constructor(values={}){
        super(values);
        console.warn('this class is deprecated now!');
    }

    //--------------------------------------对外属性及方法-----------------------------------------

    /**
     * 动画速度
     * @param speed
     */
    set speed(speed){
        this._speed=speed;
    }
    get speed(){
        return this._speed;
    }

    /**
     * 播放动画
     * @param speed {null|number} number:动画速度,null:停止
     */
    set play(speed){
        if(speed!==null&&speed!==undefined){
            cancelAnimationFrame(this._requests[0]);
            this._speed=speed;
            this._time=0;
            let ani=()=>{
                this._time+=this._speed;
                this._time=this._time%1000;
                this.material.uniforms.time.value=this._time;
                this._requests[0]=requestAnimationFrame(ani);
            };
            ani();
        }else{
            cancelAnimationFrame(this._requests[0]);
            this._requests[0]=null;
            this._time=0;
        }
    }

    /**
     * 中心区域颜色
     */
    get color(){
        return this._props.color.value;
    }
    set color(color){
        this._props.color.value=color;
    }

    /**
     * 外圈半径
     */
    get radius(){
        return this._props.radius.value;
    }
    set radius(num){
        this._props.radius.value=num;
    }

    /**
     * 片元着色器
     * @returns {string}
     */
    get fragmentShader(){
        return `
            #define PI 3.1415926
            uniform float opacity;
            uniform float time;
            uniform vec3 color;
            uniform float radius;
            varying vec2 vuv;
            float d=0.;
            vec3 yellow=vec3(0.8,0.8,0.8);//yellow和white反了
            vec3 bg_color=vec3(0.);
            float clampR(float n){
                if(n<0.)return 0.;
                if(n>1.)return 1.;
                return n;
            }
            float drawCircle(float radius,float thick){
               float l= distance(vuv,vec2(0.5));
               float a=abs(radius-l)/thick;
               return 1.-clampR(a);
            }
            void main(){
               vec3 colY=vec3(0.);
               vec3 colW=vec3(0.);
               vec4 fColW=vec4(0.);
               vec4 fColY=vec4(0.);
               vec4 fColA=vec4(0.);
               float a=0.;

               d=drawCircle(0.2*radius,0.04);
               colY=yellow*clampR(sin(d)*2.);
               if(colY.x+colY.y+colY.z>0.1)a=-1.;
               if(a!=-1.){
                  d=drawCircle(0.,0.13);
                  colW=color*clampR(sin(d)*2.);
               }
               if(colW.x+colW.y+colW.z>0.1)a=-2.;
               vec3 fCol=vec3(0.);
               if(a==-1.){
                  fColY=vec4(colY,1.);
               }else if(a==-2.){
                  fColW=vec4(colW,1.);
               }
               vec2 tuv=(vuv-.5);
               float dis=length(tuv);
               float md=mod(dis-time,0.17)*10.;
               float ad=0.5-dis;
               float alpha=ad*md+ad;
               fColA=vec4(bg_color,alpha*1.);
               fCol=fColY.rgb+fColW.rgb+fColA.rgb;
               float fA=(fColY.a+fColW.a)*0.8+fColA.a;
               gl_FragColor=vec4(fCol*fA,fA*opacity);
            }
            `;
    }

    /**
     * 设置相机控制（crossEvent用于交互,camera用于设置射线）
     * @param camCtr
     */
    set camCtr(camCtr){
        if(camCtr){
            if(this._camCtr!==null)return;
            this._camCtr=camCtr;
            this._camCtr.crossEvent.addEventListener('pointMove',this.onPointMove);
            this._camCtr.crossEvent.addEventListener('pointDown',this.onPointDown);
            this._camCtr.crossEvent.addEventListener('pointUp',this.onPointUp);
            this._camCtr.crossEvent.addEventListener('pointOut',this.onPointOut);
        }else{
            if(this._camCtr===null)return;
            this._camCtr.crossEvent.removeEventListener('pointMove',this.onPointMove);
            this._camCtr.crossEvent.removeEventListener('pointDown',this.onPointDown);
            this._camCtr.crossEvent.removeEventListener('pointUp',this.onPointUp);
            this._camCtr.crossEvent.removeEventListener('pointOut',this.onPointOut);
            this._camCtr=null;
        }
    }

    /**
     * 开始回调
     * @param func_bool
     */
    set onStart(func_bool){
        this._startCall=func_bool;
    }

    /**
     * 结束回调
     * @param func_bool
     */
    set onEnd(func_bool){
        this._endCall=func_bool;
    }

    /**
     * 悬停回调
     * @param func_bool
     */
    set onHover(func_bool){
        this._hoverCall=func_bool;
    }

    /**
     * 按下回调
     * @param func_bool
     */
    set onPress(func_bool){
        this._pressCall=func_bool;
    }

    /**
     * 点击回调
     * @param func
     */
    set onClick(func){
        this._clickCall=func;
    }

    /**
     * 设置射线检测区域（当实际区域与相机视口不同时）
     */
    setRect(left,top,width,height){
        if(!this._rect)this._rect={};
        this._rect.left=left;
        this._rect.top=top;
        this._rect.width=width;
        this._rect.height=height;
    }

    /**
     * 设置射线
     * @param pointer
     */
    setRaycaster(pointer){
        let rect = this._rect||this._camCtr.rect;
        let x = (pointer.x - rect.left) / rect.width;
        let y = (pointer.y - rect.top) / rect.height;
        this._pointerVector.set((x * 2) - 1, 1 - (y * 2));
        this._raycaster.setFromCamera(this._pointerVector, this._camCtr.camera);
    }

    /**
     * 销毁
     */
    dispose(){
        super.dispose();
        this.camCtr=null;
        this.play=null;
        this._time=null;
        this._speed=null;
        this._requests=null;
        this._raycaster=null;
        this._pointerVector=null;
        this._isHover=null;
        this._isPress=null;
        this._hoverCall=null;
        this._startCall=null;
        this._endCall=null;
        this._pressCall=null;
        this._clickCall=null;
        this._rect=null;
    }

    //------------------------------------------私有属性及方法-------------------------------------

    _init(){
        super._init();
        this._initEventBind();
    }
    _initProps() {
        super._initProps();
        this._props.add({
            color: this._values.color || new THREE.Color(0.3, 1, 0),
            radius: this._values.radius || 1,
        });
    }
    _initPropCallback() {
        super._initPropCallback();
        this._props.onKeyChange('color',(_new,_old)=>{
            this.material.uniforms.color.value=_new;
        });
        this._props.onKeyChange('radius',(_new,_old)=>{
            this.material.uniforms.radius.value=_new;
        });
    }

    _initEventBind(){
        this.onPointMove=(e)=>{
            if(!this.visible)return;
            this.setRaycaster(e.isMouse ? new THREE.Vector2(e.clientX, e.clientY) : new THREE.Vector2(e.touches[0].clientX, e.touches[0].clientY));
            let intersection = this._raycaster.intersectObject(this,false);
            let _isHover=intersection.length>0;
            if(this._isHover===_isHover)return;
            this._isHover=_isHover;
            this._hoverCall(this._isHover);
        };
        this.onPointDown=(e)=>{
            if(!this.visible)return;
            this.setRaycaster(e.isMouse ? new THREE.Vector2(e.clientX, e.clientY) : new THREE.Vector2(e.touches[0].clientX, e.touches[0].clientY));
            let intersection= this._raycaster.intersectObject(this,false);
            let _isPress=intersection.length>0;
            if(_isPress)this._startCall();
            if(this._isPress===_isPress)return;
            this._isPress=_isPress;
            this._pressCall(this._isPress);
        };
        this.onPointOut=()=>{
            if(!this.visible)return;
            if(this._isPress) {
                this._isPress = false;
                this._pressCall(this._isPress);
                this._endCall();
            }
            if(this._isHover){
                this._isHover=false;
                this._hoverCall(this._isHover);
            }
        };
        this.onPointUp=(e)=> {
            if(!this.visible)return;
            if (!this._isPress)return;
            this._endCall();
            this._isPress = false;
            this._pressCall(this._isPress);
            this.setRaycaster(e.isMouse ? new THREE.Vector2(e.clientX, e.clientY) : new THREE.Vector2(e.changedTouches[0].clientX, e.changedTouches[0].clientY));
            let intersection = this._raycaster.intersectObject(this, false);
            if (intersection.length === 0)return;
            this._clickCall();
        };
    }
    _initVariable(){
        super._initVariable();
        this._time=0;
        this._requests=[null];
        this._speed=0.001;
        this._camCtr=null;
        this._raycaster=new THREE.Raycaster();
        this._pointerVector=new THREE.Vector2();
        this._isHover=false;
        this._isPress=false;
        this._rect=null;
        this._startCall=()=>{};
        this._endCall=()=>{};
        this._hoverCall=()=>{};
        this._pressCall=()=>{};
        this._clickCall=()=>{};
    }
    _initMaterial(){
        super._initMaterial();
        this.material.fragmentShader=this.fragmentShader;
        this.material.uniforms.time={value:this._time};
        this.material.uniforms.color={value:this._props.color.value};
        this.material.uniforms.radius={value:this._props.radius.value};
        this.material.needsUpdate=true;
        this.material.blending=THREE.NormalBlending;
    }
}
